/**
 * 是否为数字
 *
 * @param v - 要检查的值
 */
export const isNumeric = (v: unknown): boolean => {
  if (Array.isArray(v)) return false;
  return !isNaN(parseFloat(v as string)) && isFinite(v as number);
};

/**
 * 过滤任意类型为数字类型，非数字类型时，使用 dft 的值，dft 未指定时，默认为 0。
 *
 * @param value -
 * @param dft - 默认值，这里不会检查该值是否为一个 int ，请确保该值为 number 类型
 */
export const filterNumeric = (value: unknown, dft = 0): number => {
  if (typeof value === 'boolean') {
    return value ? 1 : 0;
  }
  if (!isNumeric(value)) return dft;
  // try return value as original
  if (typeof value === 'number') return value;
  return parseFloat(value as string);
};

/**
 * 以最小值过滤 value 为整型值
 * @param value -
 * @param min - 最小值
 * @param dft - 默认值
 */
export const filterNumericWithMin = (value: unknown, min: number, dft = 0): number => {
  const v = filterNumeric(value, dft);
  return v < min ? min : v;
};

/**
 * 以最大值过滤 value 为整型值
 * @param value -
 * @param max - 最大值
 * @param dft - 默认值
 */
export const filterNumericWithMax = (value: unknown, max: number, dft = 0): number => {
  const v = filterNumeric(value, dft);
  return v > max ? max : v;
};

/**
 * 以最小最大值过滤 value 为整型值
 * @param value -
 * @param min - 最小值
 * @param max - 最大值
 * @param dft - 默认值
 */
export const filterNumericWithMinMax = (value: unknown, min: number, max: number, dft = 0): number => {
  const v = filterNumeric(value, dft);
  return v < min ? min : (v > max ? max : v);
};

export function random(min: number, max: number): number {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1) + min); // The maximum is inclusive and the minimum is inclusive
}

/**
 * 10进制数值（浮点）取舍算法
 *
 * exp 表示为精确的位数，取值 +x ~ -x，诸如：
 *
 * - 2 表示十位
 * - 1 表示个位
 * - -1 表示十分位
 * - -2 表示百分位
 * - -3 表示千分位
 * - .... 以此类推
 *
 * @reference: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/round#%E5%B0%8F%E6%95%B0%E8%88%8D%E5%85%A5
 * @see https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/round#%E5%B0%8F%E6%95%B0%E8%88%8D%E5%85%A5
 *
 * @param type
 * @param value
 * @param exp
 */
export function decimalAdjust(
  type: 'round' | 'ceil' | 'floor',
  value: number,
  exp?: number,
): number {
  // If the exp is undefined or zero...
  if (typeof exp === 'undefined' || +exp === 0) {
    return Math[type](value);
  }
  value = +value;
  exp = +exp;
  // If the value is not a number or the exp is not an integer...
  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
    return NaN;
  }
  // Shift
  // @ts-ignore value to string
  value = value.toString().split('e');
  // @ts-ignore here
  value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
  // Shift back
  // @ts-ignore value to string
  value = value.toString().split('e');
  // @ts-ignore here
  return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
}

/**
 * 四舍五入
 *
 * exp 表示为精确的位数，取值 +x ~ -x，诸如：
 *
 * - 2 表示十位
 * - 1 表示个位
 * - -1 表示十分位
 * - -2 表示百分位
 * - -3 表示千分位
 * - .... 以此类推
 *
 * @param value
 * @param exp
 */
export const round10 = (value: number, exp?: number): number => decimalAdjust('round', value, exp);

/**
 * 根据 exp 往下取舍，被舍的精度不进位
 *
 * 返回小于等于一个给定数字的最大整数
 *
 * `Math.floor(0.5)` => `0`
 * `Math.floor(1.5)` => `1`
 *
 * exp 表示为精确的位数，取值 +x ~ -x，诸如：
 *
 * - 2 表示十位
 * - 1 表示个位
 * - -1 表示十分位
 * - -2 表示百分位
 * - -3 表示千分位
 * - .... 以此类推
 *
 * @param value
 * @param exp
 */
export const floor10 = (value: number, exp?: number): number => decimalAdjust('floor', value, exp);

/**
 * 根据 exp 往上取舍，被舍的精度进位
 *
 * 返回大于等于给定数字的最小整数
 *
 * `Math.ceil(0.5)` => `1`
 * `Math.ceil(1.5)` => `2`
 *
 * exp 表示为精确的位数，取值 +x ~ -x，诸如：
 *
 * - 2 表示十位
 * - 1 表示个位
 * - -1 表示十分位
 * - -2 表示百分位
 * - -3 表示千分位
 * - .... 以此类推
 *
 * @param value
 * @param exp
 */
export const ceil10 = (value: number, exp?: number): number => decimalAdjust('ceil', value, exp);

